package cn.jnetty.remoting.code;
import io.netty.buffer.ByteBuf;
import io.netty.channel.ChannelHandlerContext;
import io.netty.handler.codec.ByteToMessageDecoder;
import io.netty.handler.codec.MessageToByteEncoder;
import java.util.List;

/**
 * @author:猪哥亮
 * @创建时间:2019/3/15.
 * @文件描述:
 */
public class JnettyCodecAdapterImpl implements JnettyCodecAdapter{
    /**魔法值（short）+模块号（short）+命令号（byte）+数据长度（int）+数据 = 2+2+1+4+= = */
    protected static final int HEADER_LENGTH = 2+4+2+1+4;
    // magic header.
    /**魔法值*/
    protected static final short MAGIC = (short) 3434;
    private final io.netty.channel.ChannelHandler ecode = new InternalEncoder();
    private final io.netty.channel.ChannelHandler decode = new InternalDecoder();
    @Override
    public io.netty.channel.ChannelHandler getEncoder() {
        return ecode;
    }

    @Override
    public io.netty.channel.ChannelHandler getDecoder() {
        return decode;
    }
    private class InternalEncoder extends MessageToByteEncoder<JnettyTcpWrapperIoMessage> {

        @Override
        protected void encode(ChannelHandlerContext ctx, JnettyTcpWrapperIoMessage msg, ByteBuf out) throws Exception {
            /**魔法值（short）+状态码、消息类型（byte）+模块号（short）+命令号（byte）+数据长度（int）+数据 = 2+2+1+4+= = */
            //协议头
            out.writeShort(MAGIC);
            out.writeInt(msg.getRpcId());
            //状态码、消息类型（byte）
            out.writeByte(msg.getStatus());
            //模块号
            out.writeShort(msg.getModule());
            //命令号
            out.writeByte(msg.getCmd());
            //数据长度
            out.writeInt(msg.length());
            if(msg.length() > 0){
                //字节数据Request,Response等...
                out.writeBytes(msg.getMsg());
            }
        }
    }
    private class InternalDecoder extends ByteToMessageDecoder {
        @Override
        protected void decode(ChannelHandlerContext ctx, ByteBuf input, List<Object> out) throws Exception {
            int i = input.readableBytes();
            if (i >= HEADER_LENGTH) {
                //第一个可读数据包的起始位
                int beginIndex;
                while (true) {
                    //包头开始移动游标位置
                    beginIndex = input.readerIndex();
                    //标记初始读游标位
                    input.markReaderIndex();
                    //协议头
                    if (input.readShort() == MAGIC) {
                        //一直循环直到读取到包头为止跳出循环执行下一个语句
                        break;
                    }
                    input.resetReaderIndex();
                    input.readByte();
                    //不满足
                    if (input.readableBytes() < HEADER_LENGTH) {
                        return;
                    }
                }
                int rpcId = input.readInt();
                //请求模块（哪个类）
                short module = input.readShort();
                //请求命令（类的哪个方法）
                byte cmd = input.readByte();
                //读取数据长度
                int length = input.readInt();
                if (length < 0 || length > 102400) {
                    //没有数据过来就关闭链
                    input.skipBytes(input.readableBytes());
                    ctx.channel().close();
                }
                int ss = input.readableBytes();
                //数据包没到齐
                if (ss < length) {
                    //游标归到初始位置
                    input.readerIndex(beginIndex);
                    //直接返回等待数据完整
                    return;
                }
                byte[] data = new byte[length];
                input.readBytes(data);
                JnettyTcpWrapperIoMessage ioMessage = new JnettyTcpWrapperIoMessage(rpcId,module, cmd, data);
                out.add(ioMessage);
            }
            //数据不完整，等待完整的数据包
            return;
        }
    }
}
